package org.example.service.impl;

import com.alibaba.druid.sql.ast.expr.SQLCaseExpr;
import jakarta.annotation.PostConstruct;
import org.example.config.CacheConfig;
import org.example.config.RedisLockUtilConfig;
import org.example.dao.ItemDOMapper;
import org.example.dao.ItemStockDOMapper;
import org.example.dataobject.ItemDO;
import org.example.dataobject.ItemStockDO;
import org.example.error.BusinessException;
import org.example.error.EmBusinessError;
import org.example.service.CacheService;
import org.example.service.ItemService;
import org.example.service.PromoService;
import org.example.service.model.ItemModel;
import org.example.service.model.PromoModel;
import org.example.validator.ValidationResult;
import org.example.validator.Validatorimpl;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import java.lang.ref.WeakReference;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

/**
 * @Author itmei
 * @Package org.example.service.impl
 * @Date 2025/6/1 11:08
 */
@Service
public class ItemServiceImpl implements ItemService {
    private static final Logger logger = LoggerFactory.getLogger(ItemServiceImpl.class);
    // 热点商品阈值常量，可根据实际业务调整
    private static final int HOT_SALES_THRESHOLD = 100; // 销量超过100的商品视为热点商品
    private static final int HOT_ITEMS_LIMIT = 10; // 默认热点商品数量限制

    @Autowired
    private RedisLockUtilConfig  redisLockUtilConfig;
    @Autowired
    private Validatorimpl validator;
    @Autowired
    private ItemDOMapper itemDOMapper;
    @Autowired
    private ItemStockDOMapper itemStockDOMapper;
    @Autowired
    private PromoService promoService;
    @Autowired
    private CacheManager  cacheManager;
    @Autowired
    private CacheService cacheService;

    //为每个商品ID创建独立锁，锁对象使用弱引用，避免内存泄漏。只要没有其他强引用指向锁对象，锁对象就会被垃圾回收。
    private final ConcurrentHashMap<Integer, WeakReference<Lock>> stockLocks=new ConcurrentHashMap<>();

    private ItemDO converItemDOFromItemModel(ItemModel itemModel){
        logger.info("Converting ItemModel to ItemDO: {}", itemModel);
        if(itemModel==null){
            logger.warn("ItemModel is null, returning null ItemDO");
            return null;
        }
        ItemDO itemDO=new ItemDO();
        BeanUtils.copyProperties(itemModel,itemDO);
        itemDO.setPrice(itemModel.getPrice().doubleValue());
        logger.debug("Converted ItemDO: {}", itemDO);
        return itemDO;

    }
    private ItemStockDO converItemStockDOFromItemModel(ItemModel itemModel){
        logger.info("Converting ItemModel to ItemStockDO: {}", itemModel);
        if(itemModel==null){
            logger.warn("ItemModel is null, returning null ItemStockDO");
            return null;
        }
        ItemStockDO itemStockDO = new ItemStockDO();
        itemStockDO.setItemId(itemModel.getId());
        itemStockDO.setStock(itemModel.getStock());
        logger.debug("Converted ItemStockDO: {}", itemStockDO);
        return itemStockDO;
    }
    @Override
    @Transactional
    @CacheEvict(value = "items",key="#itemModel.id")
    public ItemModel createItem(ItemModel itemModel) throws BusinessException {
        logger.info("Starting to create item: {}", itemModel);
        //校验入参
        ValidationResult validationResult = validator.validate(itemModel);
        if(validationResult.isHasErrors()){
            logger.error("Item validation failed: {}", validationResult.getErrMsg());
            throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, validationResult.getErrMsg());
        }

        //转化itemModel->dataobject
        ItemDO itemDO = this.converItemDOFromItemModel(itemModel);

        //写入数据库
        itemDOMapper.insertSelective(itemDO);
        itemModel.setId(itemDO.getId());
        logger.debug("Inserted ItemDO with id: {}", itemDO.getId());

        ItemStockDO itemStockDO = this.converItemStockDOFromItemModel(itemModel);
        itemStockDOMapper.insertSelective(itemStockDO);
        logger.debug("Inserted ItemStockDO for item id: {}", itemModel.getId());

        //返回创建完成的对象
        ItemModel result = this.getItemById(itemModel.getId());
        logger.info("Successfully created item with id: {}", result.getId());
        return result;
    }

    /**
     * 列出所有商品
     * @return
     */
    @Override
    public List<ItemModel> listItem() {
        logger.info("Listing all items");
        List<ItemDO> itemDOList = itemDOMapper.listItem();
        logger.debug("Found {} items in database", itemDOList.size());

        List<ItemModel> itemModelList = itemDOList.stream().map(itemDO -> {
            ItemStockDO itemStockDO = itemStockDOMapper.selectByItemId(itemDO.getId());
            ItemModel itemModel = this.converModelFromDataObject(itemDO, itemStockDO);
            return itemModel;
        }).collect(Collectors.toList());

        logger.info("Converted {} items to ItemModel list", itemModelList.size());
        return itemModelList;
    }

    /**
     * 根据商品Id获取商品详情
     * @param id
     * @return
     */
    @Cacheable(value = "items",key="#id",unless="#result == null")
    @Override
    public ItemModel getItemById(Integer id) {
        logger.info("Getting item by id: {}", id);
        if (id == null) {
            logger.warn("Item id is null");
            return null;
        }

        ItemDO itemDO = itemDOMapper.selectByPrimaryKey(id);
        if(itemDO == null){
            logger.warn("Item not found for id: {}", id);
            return null;
        }
        logger.debug("Found ItemDO: {} for id: {}", itemDO, id);

        //操作拿到库存数量
        ItemStockDO iteStockDO = itemStockDOMapper.selectByItemId(itemDO.getId());
        if(iteStockDO == null){
            logger.warn("ItemStockDO not found for item id: {}", itemDO.getId());
            return null;
        }
        logger.debug("Found ItemStockDO: {} for item id: {}", iteStockDO, itemDO.getId());

        //将dataobject->model
        ItemModel itemModel = converModelFromDataObject(itemDO, iteStockDO);
        //获取活动商品信息,判断是否该商品存在秒杀活动
        PromoModel promoModel = promoService.getPromoByItemId(itemModel.getId());
        if(promoModel != null && promoModel.getStatus() != 3){
            itemModel.setPromoModel(promoModel);
            logger.debug("Added promo model: {} to item: {}", promoModel, itemModel.getId());
        }

        logger.info("Successfully retrieved item: {} for id: {}", itemModel, id);
        return itemModel;
    }

    /**
     * 减少商品库存
     * @param itemId
     * @param amount
     * @return
     * @throws BusinessException
     */

    @Override
    @CacheEvict(value = "items",key="#itemId")
    public boolean decreaseStock(Integer itemId, Integer amount) throws BusinessException {
        logger.info("Decreasing stock for item id: {} by amount: {}", itemId, amount);
        if (itemId == null || amount == null || amount <= 0) {
            logger.error("Invalid parameters for decreaseStock - itemId: {}, amount: {}", itemId, amount);
            throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, "商品ID和数量必须为正数");
        }
        try {
            //双重检索库存(防止锁等待时间库存被其他线程耗尽)
            ItemStockDO itemStockDO = itemStockDOMapper.selectByItemId(itemId);
            if(itemStockDO.getStock()<amount){
                logger.warn("Insufficient stock for item id: {} to decrease by amount: {}", itemId, amount);
                return false;
            }
            //执行库存扣减，以及乐观锁来保底库存的校验
            int affectedRow=itemStockDOMapper.decreaseStock(itemId,amount,itemStockDO.getVersion());
            if(affectedRow<=0){
                logger.warn("Failed to decrease stock for item id: {} by amount: {}", itemId, amount);
                return false;
            }
            //异步删除缓存
            CompletableFuture.runAsync(() -> {
                try {
                    Thread.sleep(1000); // 延迟1秒
                    cacheService.deleteCache("items",itemId.toString());
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            });
            return affectedRow>0;
        } catch (Exception e) {
            System.err.println("decreaseStock发生异常：");
            e.printStackTrace(); // 直接打印堆栈到控制台
            logger.error("Error decreasing stock...", e); // 保留原日志
            logger.error("Error decreasing stock for item id: {} by amount: {}", itemId, amount, e);
            throw new BusinessException(EmBusinessError.UNKNOW_ERROR, "库存扣减失败：" + e.getMessage());
        }
    }

    /**
     * 增加商品销量
     * @param itemId
     * @param amount
     * @throws BusinessException
     */
    @Override
    @CacheEvict(value = "items",key="#itemId")
    public void increaseSales(Integer itemId, Integer amount) throws BusinessException {
        logger.info("Increasing sales for item id: {} by amount: {}", itemId, amount);
        if (itemId == null || amount == null || amount <= 0) {
            logger.error("Invalid parameters for increaseSales - itemId: {}, amount: {}", itemId, amount);
            throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, "商品ID和数量必须为正数");
        }

        itemDOMapper.increaseSales(itemId, amount);

        // 延迟删除缓存
        CompletableFuture.runAsync(() -> {
            try {
                Thread.sleep(1000); // 延迟1秒
                cacheService.deleteCache("items",itemId.toString());
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });

        logger.info("Successfully increased sales for item id: {} by amount: {}", itemId, amount);
    }



    /**
     * 分页查询商品列表,判断商品是否是活动商品
     * @param pageNum
     * @param pageSize
     * @return
     */
    @Override
    public List<ItemModel> listItemByPage(int pageNum, int pageSize) {
        logger.info("分页查询商品列表,页码:{} 每页数量:{}",pageNum,pageSize);
        if(pageNum<1) pageNum=1;
        if(pageNum<1||pageSize>1000){
            pageSize=10;
        }
        int offset=(pageNum-1)*pageSize;
        List<ItemDO> itemDOList = itemDOMapper.listItemByPage(offset, pageSize);
        List<ItemModel> itemModels=itemDOList.stream().map(itemDO ->
        {
            ItemStockDO itemStockDO = itemStockDOMapper.selectByItemId(itemDO.getId());
            ItemModel itemModel = this.converModelFromDataObject(itemDO,itemStockDO);
            PromoModel promoModel = promoService.getPromoByItemId(itemModel.getId());
            if(promoModel != null && promoModel.getStatus() != 3){
                itemModel.setPromoModel(promoModel);
            }
            return itemModel;
        }).collect(Collectors.toList());
        logger.info("成功分页查询商品列表,共查询到{}条数据",itemModels.size());
        return itemModels;
    }

    /**
     * 筛选出热门商品，是销量大于阈值
     * @param limit
     * @return
     */
    @Override
    public List<ItemModel> listHotItems(int limit) {
        if(limit<1){
            limit=HOT_ITEMS_LIMIT;
        }
        List<ItemDO> itemDOlList = itemDOMapper.listHotItemsBySales(limit, HOT_SALES_THRESHOLD);

        List<ItemModel> itemModels=itemDOlList.stream().map(itemDO -> {
            ItemStockDO itemStockDO = itemStockDOMapper.selectByItemId(itemDO.getId());
            ItemModel itemModel=this.converModelFromDataObject(itemDO,itemStockDO);
            //获取活动商品信息
            PromoModel promoModel = promoService.getPromoByItemId(itemModel.getId());
            if(promoModel != null && promoModel.getStatus() != 3){
                itemModel.setPromoModel(promoModel);
            }
            return itemModel;
        }).collect(Collectors.toList());
        return itemModels;
    }

    private ItemModel converModelFromDataObject(ItemDO itemDO, ItemStockDO itemStockDO){
        logger.info("Converting ItemDO: {} and ItemStockDO: {} to ItemModel", itemDO, itemStockDO);
        if(itemDO == null || itemStockDO == null){
            logger.warn("ItemDO or ItemStockDO is null");
            return null;
        }

        ItemModel itemModel = new ItemModel();
        BeanUtils.copyProperties(itemDO, itemModel);
        itemModel.setPrice(new BigDecimal(itemDO.getPrice()));
        itemModel.setStock(itemStockDO.getStock());

        logger.debug("Converted ItemModel: {}", itemModel);
        return itemModel;
    }
    //在项目启动时预加载热点商品数据到缓存

    /**
     * @PostConstruct注解，是项目启动之前就将商品进行预加载到缓存中，避免在请求时再查询数据库
     */
    @PostConstruct
    public void preloadHotItems() {
        logger.info("开始预加载热点商品数据到缓存");
        try{
            //
            List<ItemModel> hotItems=listHotItems(50);
            for(ItemModel itemModel:hotItems){
                getItemById(itemModel.getId());
            }
            logger.info("成功预加载 {} 个热点商品到缓存", hotItems.size());
        } catch (Exception e) {
            logger.error("预加载热点商品数据到缓存失败", e);
        }
    }

    /**
     * 定时刷新热点数据（每30分钟执行一次）
     * cron表达式含义：秒 分 时 日 月 周
     * 0 0/30 * * * ? 表示每30分钟执行一次
     */
    @Scheduled(cron = "0 0/30 * * * ?")
    public void refreshHotItemsCache() {
        logger.info("开始定时刷新热点商品缓存");
        try {
            // 1. 第一步：查询当前所有热点商品ID（仅操作热点商品，不影响其他缓存）
            List<ItemModel> oldHotItems = listHotItems(50);
            List<Integer> hotItemIds = oldHotItems.stream()
                    .map(ItemModel::getId)
                    .collect(Collectors.toList());

            // 2. 第二步：逐个删除旧热点商品缓存（避免批量清空导致的缓存雪崩）
            for (Integer itemId : hotItemIds) {
                try {
                    cacheService.deleteCache("items", itemId.toString()); // 假设cacheService支持按key删除
                    logger.debug("删除旧热点商品缓存，itemId: {}", itemId);
                } catch (Exception e) {
                    logger.error("删除旧缓存失败，itemId: {}", itemId, e);
                    // 单个缓存删除失败不影响整体，继续处理下一个
                }
            }
            // 3. 第三步：重新加载新热点商品到缓存（复用预加载逻辑）
            preloadHotItems();
            logger.info("定时刷新热点商品缓存完成");
        } catch (Exception e) {
            logger.error("定时刷新热点商品缓存失败", e);
            // 缓存刷新失败报警，避免影响业务
        }
    }
}